// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

// 防止头文件重复包含

#include "Components/GameFrameworkInitStateInterface.h"
#include "Components/PawnComponent.h"

// 包含所需头文件：
// - GameFrameworkInitStateInterface: 游戏框架初始化状态接口
// - PawnComponent:  pawn组件基类

#include "GameplayAbilitySpecHandle.h"
#include "LyraHeroComponent.generated.h"

// 包含游戏能力系统相关和UE代码生成头文件

namespace EEndPlayReason { enum Type : int; }
struct FLoadedMappableConfigPair;
struct FMappableConfigPair;

// 前向声明

class UGameFrameworkComponentManager;
class UInputComponent;
class ULyraCameraMode;
class ULyraInputConfig;
class UObject;
struct FActorInitStateChangedParams;
struct FFrame;
struct FGameplayTag;
struct FInputActionValue;

/**
 * 为玩家控制的pawn（或模拟玩家的机器人）设置输入和相机处理的组件。
 * 这依赖于PawnExtensionComponent来协调初始化。
 */
UCLASS(Blueprintable, Meta=(BlueprintSpawnableComponent))
// UCLASS宏参数：
// - Blueprintable: 可在蓝图中使用
// - BlueprintSpawnableComponent: 可在蓝图中生成
class LYRAGAME_API ULyraHeroComponent : public UPawnComponent, public IGameFrameworkInitStateInterface
// 继承自Pawn组件并实现初始化状态接口
{
	GENERATED_BODY()

public:

	ULyraHeroComponent(const FObjectInitializer& ObjectInitializer);

	/** 如果指定actor上存在英雄组件，则返回它 */
	UFUNCTION(BlueprintPure, Category = "Lyra|Hero")
	static ULyraHeroComponent* FindHeroComponent(const AActor* Actor) { return (Actor ? Actor->FindComponentByClass<ULyraHeroComponent>() : nullptr); }

	/** 从活动游戏能力中覆盖相机模式 */
	void SetAbilityCameraMode(TSubclassOf<ULyraCameraMode> CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle);

	/** 清除设置的相机覆盖 */
	void ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& OwningSpecHandle);

	/** 添加模式特定的输入配置 */
	void AddAdditionalInputConfig(const ULyraInputConfig* InputConfig);

	/** 移除已添加的模式特定输入配置 */
	void RemoveAdditionalInputConfig(const ULyraInputConfig* InputConfig);

	/** 如果这是由真实玩家控制并且已经进展到可以添加额外输入绑定的初始化阶段，则返回true */
	bool IsReadyToBindInputs() const;
	
	/** 当能力输入准备好绑定时通过UGameFrameworkComponentManager发送的扩展事件名称 */
	static const FName NAME_BindInputsNow;

	/** 此组件实现的特性名称 */
	static const FName NAME_ActorFeatureName;

	//~ Begin IGameFrameworkInitStateInterface interface
	virtual FName GetFeatureName() const override { return NAME_ActorFeatureName; }
	virtual bool CanChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) const override;
	virtual void HandleChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) override;
	virtual void OnActorInitStateChanged(const FActorInitStateChangedParams& Params) override;
	virtual void CheckDefaultInitialization() override;
	//~ End IGameFrameworkInitStateInterface interface

protected:

	virtual void OnRegister() override;
	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

	// 初始化玩家输入的核心函数
	virtual void InitializePlayerInput(UInputComponent* PlayerInputComponent);

	// 输入处理函数
	void Input_AbilityInputTagPressed(FGameplayTag InputTag);
	void Input_AbilityInputTagReleased(FGameplayTag InputTag);

	void Input_Move(const FInputActionValue& InputActionValue);
	void Input_LookMouse(const FInputActionValue& InputActionValue);
	void Input_LookStick(const FInputActionValue& InputActionValue);
	void Input_Crouch(const FInputActionValue& InputActionValue);
	void Input_AutoRun(const FInputActionValue& InputActionValue);

	// 确定相机模式
	TSubclassOf<ULyraCameraMode> DetermineCameraMode() const;
	
	// 输入配置激活/停用回调
	void OnInputConfigActivated(const FLoadedMappableConfigPair& ConfigPair);
	void OnInputConfigDeactivated(const FLoadedMappableConfigPair& ConfigPair);

protected:

	/**
	 * 初始化输入时应添加到此玩家的输入配置。这些配置
	 * 不会在设置中注册，因为它们是在运行时添加的。如果你希望配置
	 * 对出现在设置中，请通过GameFeatureAction_AddInputConfig添加
	 * 
	 * 注意：只有在无法访问游戏功能插件时才应添加到此。
	 * 如果可以，请使用GameFeatureAction_AddInputConfig。
	 */
	UPROPERTY(EditAnywhere)
	TArray<FMappableConfigPair> DefaultInputConfigs;
	
	/** 由能力设置的相机模式 */
	UPROPERTY()
	TSubclassOf<ULyraCameraMode> AbilityCameraMode;

	/** 最后设置相机模式的能力的规格句柄 */
	FGameplayAbilitySpecHandle AbilityCameraModeOwningSpecHandle;

	/** 当玩家输入绑定已应用时为true，对于非玩家永远不会为true */
	bool bReadyToBindInputs;
};